package com.hwtx.form.domain.def.meta;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hwtx.form.domain.def.FormDetailExt;
import com.hwtx.form.domain.def.GenFormContextHolder;
import com.hwtx.form.domain.vo.FormConfigQueryVo;
import com.hwtx.form.persistence.entity.FormDefDetail;
import com.hwtx.form.util.FormUtil;
import io.geekidea.boot.framework.exception.BusinessException;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.collections4.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.hwtx.form.domain.FormConstants.*;
import static com.hwtx.form.domain.def.meta.Button.buildListExtComponents;
import static com.hwtx.form.domain.def.meta.Column.buildColumns;

@EqualsAndHashCode(callSuper = true)
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Crud extends Component {
    private boolean syncLocation = false;
    private String title;
    private Boolean loadDataOnce;
    private String rowClassNameExpr = "text-md";
    private String tableClassName = "b-a";
    private String perPageField = PAGE_SIZE;
    private String pageField = PAGE_INDEX;
    private DefaultParams defaultParams = new DefaultParams();
    private Api api;
    private Filter filter;
    private Api quickSaveItemApi;
    private List<? extends Component> bulkActions;
    private List<Object> headerToolbar;
    private List<Object> footerToolbar;
    private List<Column> columns;
    private Boolean columnsTogglable;

    public Crud() {
        super("crud");
    }

    public static Crud buildCrud(Long formId, FormDefDetail formDefDetail,
                                 List<FormConfigQueryVo> formConfigQueryList, Map<String, Object> parameters) {
        Crud crud = new Crud();
        crud.setId(getComponentId());
        crud.setName(crud.getId());
        crud.setFilter(buildFilter(formId, formConfigQueryList));
        List<Component> buttons = buildListExtComponents(formDefDetail, formConfigQueryList, crud.getName(), true, Set.of(OPERATION_HEADER, OPERATION_HEADER_BULK));
        if (CollectionUtils.isNotEmpty(buttons)) {
            crud.setBulkActions(buttons);
        }
        crud.setColumns(buildColumns(formConfigQueryList, true));
        Column opColumn = Operation.build(formConfigQueryList, formDefDetail, crud.getId(), true);
        if (opColumn != null) {
            crud.getColumns().add(opColumn);
        } else {
            FormDetailExt formDetailExt = FormUtil.getFormDetailExt(formDefDetail.getExt());
            if (formDetailExt != null &&
                    FormDetailExt.getConfigTabs(formDetailExt.getConfigTabs(), formId).contains(FormConfigType.FORM)) {
                throw new BusinessException("未设置表单入口，若无需入口，请删除表单配置");
            }
            crud.getColumns().getLast().setStyle(null);
        }
        crud.getColumns().add(Column.buildHiddenColumn(DefaultColumn.id.name(), null));
        parameters.put(FORM_ID, formId);
        parameters.putAll(FormUtil.buildListParams(formDefDetail));
        parameters.put("&", "$$");
        if (Objects.equals(formDefDetail.getPageable(), (byte) 1)) {
            crud.setApi(Api.builder().method(HTTP_POST).url(GenFormContextHolder.getDomain() + GenFormContextHolder.getContextPath() + "/form/page").data(parameters).build());
        } else {
            crud.setLoadDataOnce(true);
            crud.setApi(Api.builder().method(HTTP_GET).url(GenFormContextHolder.getDomain() + GenFormContextHolder.getContextPath() + "/form/list").data(parameters).build());
        }
        List<Object> components = Lists.newArrayList();
        components.add("statistics");
        components.add(new Pagination());
        crud.setFooterToolbar(components);
        List<Object> headerToolbar = buildHeaderToolbar(crud, formDefDetail, formConfigQueryList);
        if (crud.getBulkActions() != null) {
            headerToolbar.add("bulkActions");
        }
        crud.setHeaderToolbar(headerToolbar);
        return crud;
    }

    private static List<Object> buildHeaderToolbar(Crud crud, FormDefDetail formDefDetail, List<FormConfigQueryVo> formConfigQueryList) {
        List<Object> components = new ArrayList<>(buildListExtComponents(formDefDetail, formConfigQueryList, crud.getName(), true, Set.of(OPERATION_HEADER)));
        if (crud.getFilter() != null && CollectionUtils.isNotEmpty(components)) {
            Map<String, Object> map = Maps.newHashMap();
            map.put("type", "columns-toggler");
            map.put("align", "right");
            map.put("draggable", true);
            components.add(map);
            map = Maps.newHashMap();
            map.put("type", "drag-toggler");
            map.put("align", "right");
            components.add(map);
            return components;
        } else {
            crud.setColumnsTogglable(false);
        }
        return components;
    }

    private static Filter buildFilter(Long formId, List<FormConfigQueryVo> formConfigQueryList) {
        Filter filter = null;
        List<Component> components = buildControllers(formConfigQueryList.stream().filter(formConfigQuery -> Objects.equals(formConfigQuery.getIsQueryShow(), (byte) 1))
                .sorted(Comparator.comparing(FormConfigQueryVo::getNum)).collect(Collectors.toList()), QUERY);
        if (CollectionUtils.isNotEmpty(components)) {
            filter = new Filter();
            components.add(Hidden.buildHidden(FORM_ID, formId.toString()));
            components.addAll(getDialogDefaultButtons());
            filter.setBody(components);
        }
        return filter;
    }

    private static List<Component> getDialogDefaultButtons() {
        Button submit = new Button();
        submit.setType("submit");
        submit.setLevel("primary");
        submit.setLabel("#i18n{submit}");
        Button reset = new Button();
        reset.setType("reset");
        reset.setLabel("#i18n{reset}");
        return Lists.newArrayList(submit, reset);
    }

    @Data
    static class DefaultParams {
        private Integer pageSize = 5;
    }

    @Data
    public static class Pagination {
        // 分页类型
        private String type = "pagination";
        // 分页布局选项
        private String layout = "perPage,pager,go";
        // 每页可用条目数的选项
        private int[] perPageAvailable = new int[]{5, 10, 20, 50};
    }

    @Data
    public static class Filter {
        private String title = "";
        private String mode = "inline";
        private boolean wrapWithPanel = true;
        private String submitText = "";
        private String type = "group";
        private List<Component> body;
    }
}